package server;

import java.sql.Date;

/**
 * <h1>Class Statistics</h1>
 * 
 * This class contains all the statistics the server must keep track of.
 * It is implemented following the Singleton pattern to ensure that we
 * are always storing the information in the same place.
 * 
 * @author Tomas
 * @date March 5 2009
 */
public class Statistics{

	/**
	 * Single instance of the class.
	 */
	private static Statistics instance = null;
	
	protected long messagesLength = 0;
	protected long totalMessagesLength = 0;
	protected long numMessages = 0;
	protected long totalNumMessages = 0;
	protected long maxNumMessages = 0;
	protected Date dateMaxNumMessages = null;
	protected long numFiles = 0;
	protected long fileSize = 0;
	
	/**
	 * Default constructor. Initializes the single instance of the class.
	 * It is private to enforce the Singleton.
	 */
	private Statistics(){
		
		messagesLength = 0;
		numMessages = 0;
		totalMessagesLength = 0;
		totalNumMessages = 0;
		numFiles = 0;
		fileSize = 0;
		maxNumMessages = 0;
		dateMaxNumMessages = new Date(System.currentTimeMillis());
	}
	
	/**
	 * Obtains the single instance of the class.
	 * 
	 * @return
	 * 		Single instance of the class.
	 */
	public synchronized static Statistics getInstance(){
		
		if(instance == null){
			instance = new Statistics();
		}
		
		return instance;
		
	}
	
	/**
	 * Resets the partial statistics.
	 */
	public synchronized void reset(){
		
		messagesLength = 0;
		numMessages = 0;
		
	}
	
	/**
	 * Add stats for a message.
	 * 
	 * @param size
	 * 		Size of the message.
	 */
	public synchronized void addMessageLength(long size){
		
		messagesLength += size;
		numMessages++;
		totalMessagesLength += size;
		totalNumMessages++;
		
	}
	
	/**
	 * Obtains the average message length since the last reset.
	 * 
	 * @return
	 * 		Partial average message length.
	 */
	public synchronized double getAverageMessageLength(){

		if(numMessages != 0){
			return ((double) messagesLength)/numMessages;
		}else{
			return 0;
		}
		
	}
	
	/**
	 * Obtains the global average message length.
	 * 
	 * @return
	 * 		Total average message length
	 */
	public synchronized double getTotalAverageMessageLength(){
		
		if(totalNumMessages != 0){
			return ((double) totalMessagesLength)/totalNumMessages;
		}else{
			return 0;
		}
		
	}
	
	/**
	 * Obtains the total number of messages sent since last reset.
	 * 
	 * @return
	 * 		Number of messages sent.
	 */
	public synchronized long getNumMessages(){
		
		return numMessages;
		
	}
	
	/**
	 * Obtains the total number of messages sent.
	 * 
	 * @return
	 * 		Total number of messages sent.
	 */
	public synchronized long getTotalMessages(){
		
		return totalNumMessages;
		
	}
	
	/**
	 * Maximum number of messages sent in a period of time.
	 * 
	 * @return
	 * 		Maximum number of messages in a period.
	 */
	public synchronized long getMaximumMessages(){
		
		return maxNumMessages;
	}
	
	/**
	 * Date when the peak of messages happened.
	 * 
	 * @return
	 * 		Date when the peak of messages happened.
	 */
	public synchronized Date getMaximumMessagesDate(){
		
		return dateMaxNumMessages;
		
	}
	
	/**
	 * Clears the maximum number of messages sent.
	 */
	public synchronized void clearMaximumMessages(){
		
		maxNumMessages = 0;
		
	}
	
	/**
	 * Adds the size of a transfered file.
	 * 
	 * @param size
	 * 		Size of the file in bytes.
	 */
	public synchronized void addFileSize(long size){
		
		fileSize += size;
		numFiles++;
		
	}
	
	/**
	 * Obtains the number of files transfered.
	 * 
	 * @return
	 * 		Number of files transfered.
	 */
	public synchronized long getNumFiles(){
		
		return numFiles;
		
	}
	
	/**
	 * Total amount of bytes transfered.
	 * 
	 * @return
	 * 		Number of bytes transfered.
	 */
	public synchronized long getFileSize(){
		
		return fileSize;
		
	}
	
	/**
	 * Obtains the number of sessions.
	 * 
	 * @return
	 * 		Number of sessions.
	 */
	public synchronized long getNumSessions(){
		
		return ServerMonitor.getInstance().numSessions();
		
	}
	
	/**
	 * Obtains the number of conversations.
	 * 
	 * @return
	 * 		Number of conversations.
	 */
	public synchronized long getNumConversations(){
		
		return ServerMonitor.getInstance().numConversations();
		
	}
	
	/**
	 * Provides a text report
	 */
	public synchronized String toString(){
		
		String report = "STATISTICS REPORT\n";
		
		report += "Users activity:\n";
		report += "    Sessions opened: " + getNumSessions() + "\n";
		report += "    Conversations opened: " + getNumConversations() + "\n\n";
		
		report += "Load of the system:\n";
		report += "    Total number of messages sent: " + this.getTotalMessages() + "\n";
		report += "    Average size of a message: " + this.getAverageMessageLength() + " bytes\n";
		report += "    Total number of files sent: " + this.getNumFiles() + "\n";
		report += "    Size of transfered files: " + this.getFileSize() + " bytes\n";
		
		report += "Peak time:\n";
		report += "    Last peak was on " + this.getMaximumMessagesDate().toString() + "\n";
		report += "    Maximum number of messages sent: " + this.getMaximumMessages() + "\n";
		
		return report;
		
	}
}
